/*
 * @Author: weidewei
 * @Date: 2025-11-17 11:31:56
 * @LastEditors: weidewei
 * @LastEditTime: 2025-11-17 16:53:22
 * @Description:
 * @FilePath: \2025-front-face\js常见手写题\publish-subscribe.js
 */
/* 1. 创建一个对象(缓存列表)
2. on方法用来把回调函数fn都加到缓存列表中
3. emit 根据key值去执行对应缓存列表中的函数
4. off方法可以根据key值取消订阅
5.once 需要一个包装函数，解绑的时候直接传入该函数
*/
class EventEmitter {
  constructor() {
    this.events = new Map();
  }

  on(eventName, callback) {
    if (!this.events.has(eventName)) {
      this.events.set(eventName, new Set());
    }
    this.events.get(eventName).add(callback);
    return this; // 链式调用
  }

  emit(eventName, ...args) {
    if (!this.events.has(eventName)) return false;
    this.events.get(eventName).forEach((cb) => {
      try {
        cb(...args);
      } catch (err) {
        console.log(err);
      }
    });
    return this;
  }

  off(eventName, callback) {
    const callbacks = this.events.get(eventName);
    if (callback) {
      callbacks.delete(callback);
      if (this.events.get(eventName).size === 0) {
        this.events.delete(eventName);
      }
    } else {
      this.events.delete(eventName);
    }
    return this;
  }

  once(eventName, callback) {
    // 取消订阅自身
    const onceFn = (...args) => {
      callback(...args);
      this.off(eventName, onceFn);
    };
    this.on(eventName, onceFn);
    return this;
  }
}
